#include "pch.h"
#include "GetHardwareInfo.h"
#include <stdio.h>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

NAMESPACE_HARDWARE_BEGIN
CGetHardwareInfo::CGetHardwareInfo() {
}

CGetHardwareInfo::~CGetHardwareInfo() {
}

void CGetHardwareInfo::GetIdeDiskSerialNumber(char pcDest[24], const char *strUserName) {
    WinNTHDSerialNumAsPhysicalRead(pcDest);
    
    if (strlen(pcDest) == 0) {
        WinNTHDSerialNumAsScsiRead(pcDest);
        
        if (strlen(pcDest) == 0) {
            WinNTHDSerialNumWithZeroRights(pcDest);
        }
    }
    
    if(strlen(pcDest) == 0) {
        ReadVolumnSerialNum(pcDest, strUserName);
    }
}

void CGetHardwareInfo::WinNTHDSerialNumAsPhysicalRead(char pcDest[24]) {
    ZeroMemory(pcDest, 24);
    
    int nDriver = 0;
    char acDriveName[256];
    sprintf(acDriveName, "\\\\.\\PhysicalDrive%d", nDriver);
    
    HANDLE hPhysicalDriveIOCTL = CreateFileA(acDriveName,
                                 GENERIC_READ | GENERIC_WRITE,
                                 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                                 OPEN_EXISTING, 0, NULL);
                                 
    if (hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE) {
        GETVERSIONOUTPARAMS VersionParams;
        DWORD               cbBytesReturned = 0;
        
        // Get the version, etc of PhysicalDrive IOCTL
        memset((void *) &VersionParams, 0, sizeof(VersionParams));
        
        if(DeviceIoControl(hPhysicalDriveIOCTL, DFP_GET_VERSION,
                           NULL,
                           0,
                           &VersionParams,
                           sizeof(VersionParams),
                           &cbBytesReturned, NULL)) {
            if (VersionParams.bIDEDeviceMap > 0) {
                BYTE  bIDCmd = 0;   // IDE or ATAPI IDENTIFY cmd
                SENDCMDINPARAMS  scip;
                BYTE IdOutCmd[sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE];
                
                // Now, get the ID sector for all IDE devices in the system.
                // If the device is ATAPI use the IDE_ATAPI_IDENTIFY command,
                // otherwise use the IDE_ATA_IDENTIFY command
                bIDCmd = (VersionParams.bIDEDeviceMap >> nDriver & 0x10) ? \
                         IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;
                         
                memset(&scip, 0, sizeof(scip));
                memset(IdOutCmd, 0, sizeof(IdOutCmd));
                
                scip.cBufferSize = IDENTIFY_BUFFER_SIZE;
                scip.irDriveRegs.bSectorCountReg = 1;
                scip.irDriveRegs.bSectorNumberReg = 1;
                
                // Compute the drive number.
                scip.irDriveRegs.bDriveHeadReg = 0xA0 | ((nDriver & 1) << 4);
                
                // The command can either be IDE identify or ATAPI identify.
                scip.irDriveRegs.bCommandReg = bIDCmd;
                scip.bDriveNumber = nDriver;
                
                if(DeviceIoControl(hPhysicalDriveIOCTL, DFP_RECEIVE_DRIVE_DATA,
                                   (LPVOID)&scip, sizeof(SENDCMDINPARAMS) - 1,
                                   (LPVOID)&IdOutCmd,
                                   sizeof(IdOutCmd),
                                   &cbBytesReturned, NULL)) {
                    IDSECTOR *pIdSector = (IDSECTOR *)((PSENDCMDOUTPARAMS)IdOutCmd)->bBuffer;
                    
                    for(int i = 0; i < 20; i += 2) {
                        pcDest[i] = pIdSector->sSerialNumber[i + 1];
                        pcDest[i + 1] = pIdSector->sSerialNumber[i];
                    }
                }
            }
        }
        
        CloseHandle (hPhysicalDriveIOCTL);
    }
}

void CGetHardwareInfo::WinNTHDSerialNumAsScsiRead(char pcDest[24]) {
    ZeroMemory(pcDest, 24);
    
    BOOL bDone = FALSE;
    for(int controller = 0; controller < MAX_IDE_DRIVES; controller++) {
        HANDLE hScsiDriveIOCTL = 0;
        char   driveName [256];
        
        sprintf (driveName, "\\\\.\\Scsi%d:", controller);
        
        //  Windows NT, Windows 2000, any rights should do
        hScsiDriveIOCTL = CreateFileA(driveName,
                                      GENERIC_READ | GENERIC_WRITE,
                                      FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                                      OPEN_EXISTING, 0, NULL);
                                      
        if (hScsiDriveIOCTL != INVALID_HANDLE_VALUE) {
            for(int drive = 0; drive < 2; drive++) {
                char buffer [sizeof (SRB_IO_CONTROL) + SENDIDLENGTH];
                SRB_IO_CONTROL *p = (SRB_IO_CONTROL *) buffer;
                SENDCMDINPARAMS *pin = (SENDCMDINPARAMS *) (buffer + sizeof (SRB_IO_CONTROL));
                DWORD dummy;
                
                memset (buffer, 0, sizeof (buffer));
                p -> HeaderLength = sizeof (SRB_IO_CONTROL);
                p -> Timeout = 10000;
                p -> Length = SENDIDLENGTH;
                p -> ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
                strncpy ((char *) p -> Signature, "SCSIDISK", 8);
                
                pin -> irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
                pin -> bDriveNumber = drive;
                
                if (DeviceIoControl (hScsiDriveIOCTL, IOCTL_SCSI_MINIPORT,
                                     buffer,
                                     sizeof (SRB_IO_CONTROL) +
                                     sizeof (SENDCMDINPARAMS) - 1,
                                     buffer,
                                     sizeof (SRB_IO_CONTROL) + SENDIDLENGTH,
                                     &dummy, NULL)) {
                    SENDCMDOUTPARAMS *pOut = (SENDCMDOUTPARAMS *) (buffer + sizeof (SRB_IO_CONTROL));
                    
                    if(pOut->DriverStatus.bDriverError == SMART_NO_ERROR) {
                        IDSECTOR *pIdSector = (IDSECTOR *) (pOut -> bBuffer);
                        {
                            if(pIdSector -> sModelNumber [0]) {
                                for(int i = 0; i < 20; i += 2) {
                                    pcDest[i] = pIdSector->sSerialNumber[i + 1];
                                    pcDest[i + 1] = pIdSector->sSerialNumber[i];
                                }
                                
                                bDone = TRUE;
                                break;
                            }
                        }
                    }
                }
            }
            
            CloseHandle (hScsiDriveIOCTL);
        }
        
        if(bDone) {
            break;
        }
    }
}

char *CGetHardwareInfo::flipAndCodeBytes (char *str) {
    static char flipped [1000];
    int num = (int)strlen (str);
    strcpy (flipped, "");
    for (int i = 0; i < num; i += 4) {
        for (int j = 1; j >= 0; j--) {
            int sum = 0;
            for (int k = 0; k < 2; k++) {
                sum *= 16;
                switch (str [i + j * 2 + k]) {
                    case '0':
                        sum += 0;
                        break;
                    case '1':
                        sum += 1;
                        break;
                    case '2':
                        sum += 2;
                        break;
                    case '3':
                        sum += 3;
                        break;
                    case '4':
                        sum += 4;
                        break;
                    case '5':
                        sum += 5;
                        break;
                    case '6':
                        sum += 6;
                        break;
                    case '7':
                        sum += 7;
                        break;
                    case '8':
                        sum += 8;
                        break;
                    case '9':
                        sum += 9;
                        break;
                    case 'a':
                        sum += 10;
                        break;
                    case 'b':
                        sum += 11;
                        break;
                    case 'c':
                        sum += 12;
                        break;
                    case 'd':
                        sum += 13;
                        break;
                    case 'e':
                        sum += 14;
                        break;
                    case 'f':
                        sum += 15;
                        break;
                }
            }
            if (sum > 0) {
                char sub [2];
                sub [0] = (char) sum;
                sub [1] = 0;
                strcat (flipped, sub);
            }
        }
    }
    
    return flipped;
}

void CGetHardwareInfo::WinNTHDSerialNumWithZeroRights(char pcDest[24]) {
    ZeroMemory(pcDest, 24);
    
    BOOL bDone = FALSE;
    for (int drive = 0; drive < MAX_IDE_DRIVES; drive++) {
        HANDLE hPhysicalDriveIOCTL = 0;
        
        char driveName [256];
        sprintf (driveName, "\\\\.\\PhysicalDrive%d", drive);
        
        //  Windows NT, Windows 2000, Windows XP - admin rights not required
        hPhysicalDriveIOCTL = CreateFileA(driveName, 0,
                                          FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                                          OPEN_EXISTING, 0, NULL);
                                          
                                          
        if (hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE) {
            STORAGE_PROPERTY_QUERY query;
            DWORD cbBytesReturned = 0;
            char buffer [10000];
            
            memset ((void *) & query, 0, sizeof (query));
            query.PropertyId = StorageDeviceProperty;
            query.QueryType = PropertyStandardQuery;
            
            memset (buffer, 0, sizeof (buffer));
            
            if ( DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_STORAGE_QUERY_PROPERTY,
                                  & query,
                                  sizeof (query),
                                  & buffer,
                                  sizeof (buffer),
                                  & cbBytesReturned, NULL) ) {
                STORAGE_DEVICE_DESCRIPTOR *descrip = (STORAGE_DEVICE_DESCRIPTOR *) & buffer;
                
                if(descrip->SerialNumberOffset > sizeof(STORAGE_DEVICE_DESCRIPTOR)) {
                    char serialNumber [1000];
                    
                    if (strlen(buffer + descrip -> SerialNumberOffset) > 20) {
                        strcpy (serialNumber, flipAndCodeBytes(buffer + descrip -> SerialNumberOffset));
                    } else {
                        strcpy (serialNumber, buffer + descrip -> SerialNumberOffset);
                    }
                    
                    if(strlen(serialNumber) > 0) {
                        strncpy(pcDest, serialNumber, 20);
                        bDone = TRUE;
                    }
                }
            }
            
            if(!bDone) {
                memset (buffer, 0, sizeof (buffer));
                
                if ( DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER,
                                      NULL,
                                      0,
                                      & buffer,
                                      sizeof (buffer),
                                      & cbBytesReturned, NULL) ) {
                    MEDIA_SERIAL_NUMBER_DATA *mediaSerialNumber =
                        (MEDIA_SERIAL_NUMBER_DATA *) & buffer;
                    char serialNumber [1000];
                    
                    strcpy (serialNumber, (char *) mediaSerialNumber -> SerialNumberData);
                    
                    if(strlen(serialNumber) > 0) {
                        strncpy(pcDest, serialNumber, 20);
                        bDone = TRUE;
                    }
                }
            }
            
            CloseHandle (hPhysicalDriveIOCTL);
        }
        
        if(bDone) {
            break;
        }
    }
}

void CGetHardwareInfo::ReadVolumnSerialNum(char pcDest[24], const char *strUserName) {
    ZeroMemory(pcDest, 24);
    
    char acPathName[256] = {0};
    GetCurrentDirectoryA(255, acPathName);
    acPathName[3] = 0;
    
    char acVolName[256] = {0};
    DWORD dwSerialNum = 0;
    DWORD dwMaxComponentLen;
    DWORD dwFileSysFlags;
    char acFileSysName[256] = {0};
    
    GetVolumeInformationA(acPathName, acVolName, 255, &dwSerialNum, &dwMaxComponentLen, &dwFileSysFlags, acFileSysName,
                          255);
                          
    ULARGE_INTEGER nBytesAvail;
    ULARGE_INTEGER nTotalBytes;
    ULARGE_INTEGER nFreeBytes;
    
    GetDiskFreeSpaceExA("c:\\", &nBytesAvail, &nTotalBytes, &nFreeBytes);
    UINT nTotalKiloBytes = UINT(nTotalBytes.QuadPart / 1024);
    
    char acTemp[32];
    sprintf(acTemp, "%08X%8s%08X", dwSerialNum, strUserName, nTotalKiloBytes);
    
    memcpy(pcDest, acTemp, 24);
}
NAMESPACE_HARDWARE_END
